﻿using UnityEngine;
using System;
using System.Collections.Generic;

public class SoundPlayer : MonoBehaviour
{
    static bool canReFindAllPlayers = true;
    static SoundPlayer[] allSoundPlayers;
    static int allSoundPlayersCount;
    const string SAVE_KEY = "SOUND_SAVE_KEY";
    AudioSource audioSource;
    Queue<AudioClip> clipsList = new Queue<AudioClip>();
    float delayTimer, destroyTimer;
    Action onFinishCallback;
    public bool isPlaying { get { if (audioSource) return audioSource.isPlaying; return false; } }
    bool canAutoDestroy;

    /// <summary>
    /// 读取或设置全场使用SoundPlayer播放的所有音频的开关
    /// </summary>
    public static bool IsSoundOn
    {
        get { return PlayerPrefs.GetInt(SAVE_KEY, 1) == 1; }
        set
        {
            PlayerPrefs.SetInt(SAVE_KEY, value ? 1 : 0);
            if (canReFindAllPlayers)
            {
                allSoundPlayers = GameObject.FindObjectsOfType<SoundPlayer>();
                allSoundPlayersCount = allSoundPlayers.Length;
                canReFindAllPlayers = false;
            }
            for (int i = 0; i < allSoundPlayersCount; i++)
            {
                allSoundPlayers[i].audioSource.enabled = value;
            }
        }
    }

    static float _volume = 1;
    /// <summary>
    /// 读取或设置全场使用SoundPlayer播放的所有音频的音量
    /// </summary>
    public static float Volume
    {
        get { return _volume; }
        set
        {
            _volume = value;
            if (canReFindAllPlayers)
            {
                allSoundPlayers = GameObject.FindObjectsOfType<SoundPlayer>();
                allSoundPlayersCount = allSoundPlayers.Length;
                canReFindAllPlayers = false;
            }
            for (int i = 0; i < allSoundPlayersCount; i++)
            {
                allSoundPlayers[i].audioSource.volume = value;
            }
        }
    }

    public static SoundPlayer Play(float delay, AudioClip clip, Action onFinishCallback = null)
    {
        return Play(delay, clip, 1f, onFinishCallback);
    }

    public static SoundPlayer Play(float delay, AudioClip clip, float volume, Action onFinishCallback = null)
    {
        if (!IsSoundOn || !clip)
        {
            return null;
        }
        SoundPlayer soundPlayer = NewInstance();
        soundPlayer.canAutoDestroy = true;
        soundPlayer.PlayAutoDestroy(delay, clip, volume, onFinishCallback);
        return soundPlayer;
    }

    public static SoundPlayer Play(float delay, AudioClip[] clips, float volume, Action onFinishCallback = null)
    {
        SoundPlayer soundPlayer = NewInstance();
        soundPlayer.canAutoDestroy = true;
        soundPlayer.PlayAutoDestroy(delay, clips, volume, onFinishCallback);
        return soundPlayer;
    }

    /// <summary>
    /// 创建一个声音播放器，播完不会自动销毁，需调用Destroy()方法销毁
    /// </summary>
    /// <returns></returns>
    public static SoundPlayer NewInstance(string name = "")
    {
        string nameStr = "SoundPlayer";
        if (!string.IsNullOrEmpty(name)) nameStr += "_" + name;
        GameObject go = new GameObject(nameStr);
        SoundPlayer soundPlayer = go.AddComponent<SoundPlayer>();
        soundPlayer.audioSource = go.AddComponent<AudioSource>();
        return soundPlayer;
    }

    void OnDestroy()
    {
        canReFindAllPlayers = true;
    }

    void Awake()
    {
        canReFindAllPlayers = true;
    }

    private void PlayAutoDestroy(float delay, AudioClip[] clips, float volume = 1f, Action onFinishCallback = null)
    {
        clipsList.Clear();
        for (int i = 0; i < clips.Length; i++)
        {
            clipsList.Enqueue(clips[i]);
        }
        this.PlayAutoDestroy(delay, clipsList.Dequeue(), volume, onFinishCallback);
    }

    private void PlayAutoDestroy(float delay, AudioClip clip, float volume = 1f, Action onFinishCallback = null)
    {
        if (!IsSoundOn || !clip)
        {
            return;
        }
        audioSource.Stop();
        destroyTimer = delay + clip.length;
        audioSource.clip = clip;
        audioSource.playOnAwake = false;
        audioSource.loop = false;
        audioSource.volume = volume;
        this.onFinishCallback = onFinishCallback;
        if (delay <= 0f)
        {
            delayTimer = -1;
            audioSource.Play();
        }
        else
        {
            delayTimer = delay;
        }
    }

    /// <summary>
    /// 停止播放
    /// </summary>
    public void Stop()
    {
        if (audioSource)
        {
            audioSource.Stop();
        }
    }

    /// <summary>
    /// 停止播放并销毁
    /// </summary>
    public void Destroy()
    {
        Destroy(gameObject);
        if (onFinishCallback != null)
        {
            onFinishCallback();
            onFinishCallback = null;
        }
    }

    void Update()
    {
        if (delayTimer > 0f)
        {
            delayTimer -= Time.deltaTime;
            if (delayTimer <= 0f)
            {
                audioSource.Play();
            }
        }
        if (destroyTimer > 0f)
        {
            destroyTimer -= Time.deltaTime;
            if (destroyTimer <= 0f)
            {
                if (clipsList.Count > 0)
                {
                    this.PlayAutoDestroy(0, clipsList.Dequeue(), Volume, onFinishCallback);
                }
                else
                {
                    if (canAutoDestroy) Destroy();
                    if (onFinishCallback != null)
                    {
                        onFinishCallback();
                        onFinishCallback = null;
                    }
                }
            }
        }
    }
}